#pragma once

#include <web/pch.h>
#include <web/SockAddrIn.h>
#include <web/FileDesc.h>

namespace Web
{
    struct Socket : public Web::FileDesc
    {

        int InitTcp()
        {
            fd = socket(AF_INET, SOCK_STREAM, 0);
            return fd;
        };
        int InitUdp()
        {
            fd = socket(AF_INET, SOCK_DGRAM, 0); 
            return fd;
        }

        bool ErrorSock()
        {
            return fd == -1;
        }

        bool Failed(const std::string &info)
        {
            bool res = (fd == -1);

            if (res)
            {
                printf("%s", info.c_str());
                Close();
            }

            return res;
        }

        int Connect(const Web::SockAddrIn &sockAddrIn)
        {
            return connect(fd, sockAddrIn.GetSockAddr(), sizeof(struct sockaddr_in));
        }

        int Bind(const Web::SockAddrIn &sockAddr)
        {
            return bind(this->fd, sockAddr.GetSockAddr(), sizeof(struct sockaddr_in));
        }

        int Listen()
        {
            return listen(fd, SOMAXCONN);
        }

        template <typename T>
        int RecvFrom(T &revbuf, sockaddr_in &soserver)
        {
            static SOCKLEN addrlen = sizeof(struct sockaddr_in);
            return recvfrom(fd, (char *)&revbuf, sizeof(revbuf), 0, (sockaddr *)&soserver, &addrlen);
        }

        template <typename T>
        int SendTo(const T &senbuf, sockaddr_in &soserver)
        {
            static SOCKLEN addrlen = sizeof(struct sockaddr_in);
            return sendto(fd, (const char *)&senbuf, sizeof(senbuf), 0, (sockaddr *)&soserver, addrlen);
        }

        template <typename T>
        int RecvFrom(T &revbuf, SockAddrIn &sockAddrIn)
        {
            return RecvFrom<T>(revbuf, sockAddrIn.m_AddrIn);
        }

        template <typename T>
        int SendTo(const T &senbuf, SockAddrIn &sockaddrIn)
        {
            return SendTo<T>(senbuf, sockaddrIn.m_AddrIn);
        }

        int SendChar(const char *__buf, size_t __n, int __flags = 0)
        {
            return send(this->fd, __buf, __n, __flags);
        }
        int RecvChar(char *__buf, size_t __n, int __flags = 0)
        {
            return recv(this->fd, __buf, __n, __flags);
        }

        template <typename T>
        int Recv(T &t, int __flag = 0)
        {
            return recv(fd, (char *)&t, sizeof(T), __flag);
        }

        template <typename T>
        int Send(const T &t, int __flag = 0)
        {
            return send(fd, (const char *)&t, sizeof(T), __flag);
        }

        virtual ~Socket()
        {
            Close();
        }
    };
};
